package com.afdor.rws.core.extension.factory;

import com.afdor.rws.annotation.extension.Extension;
import com.afdor.rws.core.extension.ExtensionFactory;
import com.afdor.rws.core.extension.ExtensionItem;
import com.afdor.rws.core.extension.utils.ExtensionUtils;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationContext;

import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * 基于Spring实现的扩展点扫描器工厂
 *
 * @author 悭梵
 * @date Created in 2018-09-13 17:41
 */
@Slf4j
@ToString
@EqualsAndHashCode
@Extension(value = "spring", order = Extension.MAX_ORDER - 100, interfaceClass = ExtensionFactory.class)
public class SpringExtensionFactory implements ExtensionFactory {

    private static ApplicationContext APPLICATION_CONTEXT;

    @Override
    public <T> boolean hasExtension(Class<T> interfaceClass, String name) {
        return APPLICATION_CONTEXT.containsBean(ExtensionUtils.getFullExtension(interfaceClass, name));
    }

    @Override
    public <T> T newExtension(Class<T> interfaceClass, String name, Object... args) {
        throw new IllegalStateException("The extension managed by Spring can not be created.");
    }

    @Override
    public <T> T getExtension(Class<T> interfaceClass, String name) {
        return APPLICATION_CONTEXT.getBean(ExtensionUtils.getFullExtension(interfaceClass, name), interfaceClass);
    }

    @Override
    public <T> Collection<ExtensionItem<T>> loadExtensionClasses(Class<T> interfaceClass) {
        Map<String, T> springExtensionMap = APPLICATION_CONTEXT.getBeansOfType(interfaceClass);
        return (Collection) Optional
                .ofNullable(springExtensionMap)
                .orElse(Collections.emptyMap())
                .entrySet()
                .stream()
                .map(entry -> ExtensionItem
                        .builder()
                        .name(entry.getKey())
                        .extensionClass((Class) entry.getValue().getClass())
                        .build())
                .collect(Collectors.toList());
    }

    public static void setApplicationContext(ApplicationContext applicationContext) {
        APPLICATION_CONTEXT = applicationContext;
    }
}
